using System;
using System.Collections.Generic;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

using VPT = Microsoft.Xna.Framework.Graphics.VertexPositionTexture;

namespace ProjectTogepi.Graphics
{
	/// <summary>
	/// Draws shapes and other Vector Graphics
	/// </summary>
	public class VectorDraw
	{
		GraphicsDevice graphics;
		Effect effect;
		Matrix proj;

		static VertexBuffer line = null;
		VertexDeclaration verDec;

		EffectParameter lineparm;
		EffectParameter worldparm;

		/// <summary>
		/// Vector Draw constructor
		/// </summary>
		/// <param name="g">Game Class</param>
		/// <remarks>This method calls the Content Manager</remarks>
		public VectorDraw(Game g)
		{
			graphics = g.GraphicsDevice;
			effect = g.Content.Load<Effect>("vector");
			lineparm = effect.Parameters["Line"];
			worldparm = effect.Parameters["World"];

			verDec = new VertexDeclaration(graphics, VPT.VertexElements);

			CreateLine();

			Resize();
			g.Window.ClientSizeChanged += new EventHandler(Window_ClientSizeChanged);
		}

		/// <summary>
		/// Draws given part
		/// </summary>
		/// <param name="part">Vector data</param>
		public void Draw(Part part)
		{
			graphics.VertexDeclaration = verDec;
			graphics.RenderState.CullMode = CullMode.None;
			graphics.RenderState.DepthBufferEnable = false;

			graphics.Vertices[0].SetSource(line, 0, VPT.SizeInBytes);


			Part.Shape[] shapes = part.Shapes;
			Vector2[] vert;

			worldparm.SetValue(part.Translation);

			effect.Begin();
			effect.CurrentTechnique.Passes[0].Begin();
			for (int ii = 0; ii < shapes.Length; ++ii)
			{

				vert = shapes[ii].Vertices;
				Vector2 lastp = vert[0];
				Vector2 newp;
				for (int jj = 1; jj < vert.Length; ++jj)
				{
					newp = vert[jj];
					lineparm.SetValue(new Vector4(lastp.X, lastp.Y, newp.X, newp.Y));
					effect.CommitChanges();
					graphics.DrawPrimitives(PrimitiveType.TriangleFan, 0, 2);
					lastp = newp;
				}
				newp = vert[0];
				lineparm.SetValue(new Vector4(lastp.X, lastp.Y, newp.X, newp.Y));
				effect.CommitChanges();
				graphics.DrawPrimitives(PrimitiveType.TriangleFan, 0, 2);

			}
			effect.CurrentTechnique.Passes[0].End();
			effect.End();


		}

		/// <summary>
		/// Creates base mesh to draw lines
		/// </summary>
		void CreateLine()
		{
			if (line != null)
				return;

			line = new VertexBuffer(graphics, 4 * VPT.SizeInBytes, BufferUsage.WriteOnly);

			VPT[] data = new VPT[4];

			data[0] = new VPT(new Vector3(0, -2.5f, 0), new Vector2(0, 0));
			data[1] = new VPT(new Vector3(0, 2.5f, 0), new Vector2(0, 0));
			data[2] = new VPT(new Vector3(0, 2.5f, 0), new Vector2(1, 0));
			data[3] = new VPT(new Vector3(0, -2.5f, 0), new Vector2(1, 0));

			line.SetData<VPT>(data);
		}

		/// <summary>
		/// Changes the Projection matrix to fit screen
		/// </summary>
		void Resize()
		{
			PresentationParameters pp = graphics.PresentationParameters;

			Matrix.CreateTranslation(-.5f, .5f, 0, out proj);
			Matrix temp;
			Matrix.CreateOrthographicOffCenter(0, pp.BackBufferWidth, pp.BackBufferHeight, 0, 0, 1, out temp);
			Matrix.Multiply(ref proj, ref temp, out proj);

			effect.Parameters["Project"].SetValue(proj);
		}

		/// <summary>
		/// Calls resize() to change Projection matrix
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		void Window_ClientSizeChanged(object sender, EventArgs e)
		{
			Resize();
		}
	}
}
